home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
demos
/
REALITY
/
distort
/
rubber.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
6KB
|
285 lines
/*
* Copyright 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
rubber.c
Drew Olbrich, 1992
*/
#include <stdio.h>
#include <math.h>
#include <gl.h>
#include <device.h>
#include "defs.h"
#include "rubber.h"
EFFECT rubber = { rubber_init, rubber_dynamics, rubber_redraw, rubber_click };
#define SPRING_KS 0.3
#define DRAG 0.5
typedef struct {
float x[3];
float v[3];
float t[2];
int nail;
} MASS;
typedef struct {
int i, j;
float r;
} SPRING;
static int spring_count;
static MASS *mass = NULL;
static SPRING *spring = NULL;
static int grab = -1; /* index of grabbed mass point */
void rubber_init()
{
int i, j;
int k;
int m;
zbuffer(TRUE);
if (mass == NULL)
{
mass = (MASS *) malloc(sizeof(MASS)*GRID_SIZE_X*GRID_SIZE_Y);
if (mass == NULL)
{
fprintf(stderr, "rubber: Can't allocate memory.\n");
exit(-1);
}
}
k = 0;
for (i = 0; i < GRID_SIZE_X; i++)
for (j = 0; j < GRID_SIZE_Y; j++)
{
mass[k].nail = (i == 0 || j == 0 || i == GRID_SIZE_X - 1
|| j == GRID_SIZE_Y - 1);
mass[k].x[0] = i/(GRID_SIZE_X - 1.0)*WIN_SIZE_X;
mass[k].x[1] = j/(GRID_SIZE_Y - 1.0)*WIN_SIZE_Y;
mass[k].x[2] = -(CLIP_FAR - CLIP_NEAR)/2.0;
mass[k].v[0] = 0.0;
mass[k].v[1] = 0.0;
mass[k].v[2] = 0.0;
mass[k].t[0] = i/(GRID_SIZE_X - 1.0);
mass[k].t[1] = j/(GRID_SIZE_Y - 1.0);
k++;
}
if (spring == NULL)
{
spring_count = (GRID_SIZE_X - 1)*(GRID_SIZE_Y - 2)
+ (GRID_SIZE_Y - 1)*(GRID_SIZE_X - 2);
spring = (SPRING *) malloc(sizeof(SPRING)*spring_count);
if (spring == NULL)
{
fprintf(stderr, "rubber: Can't allocate memory.\n");
exit(-1);
}
}
k = 0;
for (i = 1; i < GRID_SIZE_X - 1; i++)
for (j = 0; j < GRID_SIZE_Y - 1; j++)
{
m = GRID_SIZE_Y*i + j;
spring[k].i = m;
spring[k].j = m + 1;
spring[k].r = (WIN_SIZE_Y - 1.0)/(GRID_SIZE_Y - 1.0);
k++;
}
for (j = 1; j < GRID_SIZE_Y - 1; j++)
for (i = 0; i < GRID_SIZE_X - 1; i++)
{
m = GRID_SIZE_Y*i + j;
spring[k].i = m;
spring[k].j = m + GRID_SIZE_X;
spring[k].r = (WIN_SIZE_X - 1.0)/(GRID_SIZE_X - 1.0);
k++;
}
}
/*
Do the dynamics simulation for the next frame.
*/
void rubber_dynamics(int mousex, int mousey)
{
int k;
float d[3];
int i, j;
float l;
float a;
/* calculate all the spring forces acting on the mass points */
for (k = 0; k < spring_count; k++)
{
i = spring[k].i;
j = spring[k].j;
d[0] = mass[i].x[0] - mass[j].x[0];
d[1] = mass[i].x[1] - mass[j].x[1];
d[2] = mass[i].x[2] - mass[j].x[2];
l = sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]);
if (l != 0.0)
{
d[0] /= l;
d[1] /= l;
d[2] /= l;
a = l - spring[k].r;
mass[i].v[0] -= d[0]*a*SPRING_KS;
mass[i].v[1] -= d[1]*a*SPRING_KS;
mass[i].v[2] -= d[2]*a*SPRING_KS;
mass[j].v[0] += d[0]*a*SPRING_KS;
mass[j].v[1] += d[1]*a*SPRING_KS;
mass[j].v[2] += d[2]*a*SPRING_KS;
}
}
/* update the state of the mass points */
for (k = 0; k < GRID_SIZE_X*GRID_SIZE_Y; k++)
if (!mass[k].nail)
{
mass[k].x[0] += mass[k].v[0];
mass[k].x[1] += mass[k].v[1];
mass[k].x[2] += mass[k].v[2];
mass[k].v[0] *= (1.0 - DRAG);
mass[k].v[1] *= (1.0 - DRAG);
mass[k].v[2] *= (1.0 - DRAG);
if (mass[k].x[2] > -CLIP_NEAR - 0.01)
mass[k].x[2] = -CLIP_NEAR - 0.01;
if (mass[k].x[2] < -CLIP_FAR + 0.01)
mass[k].x[2] = -CLIP_FAR + 0.01;
}
/* if a mass point is grabbed, attach it to the mouse */
if (grab != -1 && !mass[grab].nail)
{
mass[grab].x[0] = mousex;
mass[grab].x[1] = mousey;
mass[grab].x[2] = -(CLIP_FAR - CLIP_NEAR)/4.0;
}
}
/*
Draw the next frame of animation.
*/
void rubber_redraw()
{
int k;
int i, j;
zclear();
cpack(0xFFFFFFFF);
#define _WIREFRAME
#ifdef WIREFRAME
for (k = 0; k < spring_count; k++)
{
bgnline();
v3f(mass[spring[k].i].x);
v3f(mass[spring[k].j].x);
endline();
}
#else
k = 0;
for (i = 0; i < GRID_SIZE_X - 1; i++)
{
for (j = 0; j < GRID_SIZE_Y - 1; j++)
{
bgnpolygon();
t2f(mass[k].t);
v3f(mass[k].x);
t2f(mass[k + 1].t);
v3f(mass[k + 1].x);
t2f(mass[k + GRID_SIZE_Y + 1].t);
v3f(mass[k + GRID_SIZE_Y + 1].x);
t2f(mass[k + GRID_SIZE_Y].t);
v3f(mass[k + GRID_SIZE_Y].x);
endpolygon();
k++;
}
k++;
}
#endif
swapbuffers();
}
/*
Return the index of the mass point that's nearest to the
given screen coordinate.
*/
int rubber_grab(int x, int y)
{
float dx[2];
float d;
float min_d;
float min_i;
int i;
for (i = 0; i < GRID_SIZE_X*GRID_SIZE_Y; i++)
{
dx[0] = mass[i].x[0] - x;
dx[1] = mass[i].x[1] - y;
d = sqrt(dx[0]*dx[0] + dx[1]*dx[1]);
if (i == 0 || d < min_d)
{
min_i = i;
min_d = d;
}
}
return min_i;
}
/*
If the mouse is pressed down, grab the nearest mass point.
*/
void rubber_click(int mousex, int mousey, int state)
{
if (state)
grab = rubber_grab(mousex, mousey);
else
grab = -1;
}